package hichecker.ui;

import hichecker.controller.Config;
import hichecker.controller.MainController;
import hichecker.tools.event.HiCheckerEvent;
import hichecker.tools.event.abstract_event.Observable;
import hichecker.tools.event.abstract_event.Observer;
import hichecker.tools.export.CSVFile;
import hichecker.ui.components.file_chooser.OpenFileChooser;
import hichecker.ui.components.file_chooser.SaveFileChooser;
import hichecker.ui.components.file_chooser.AbstractFileChooser.FileType;
import hichecker.ui.custom_views.series.SeriesView;
import hichecker.ui.general_views.container_panel.ContainerPanel;
import hichecker.ui.general_views.container_panel.content.ContentPanel;
import hichecker.ui.general_views.toolbars.MenuBar;
import hichecker.ui.general_views.toolbars.NavigationBar;
import hichecker.university.Course;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import org.apache.log4j.Logger;

/**
 * Class showing the main window frame which interacts with the user.
 */
public class MainFrame extends JFrame implements Observer<HiCheckerEvent> {
	private Logger logger = Logger.getLogger(MainFrame.class);

	private MainController controller;
	private JPanel content;

	/**
	 * Creates the frame and allocates the {@link MainController}
	 * @param controller
	 */
	public MainFrame(MainController controller) {
		this.controller = controller;
		this.controller.addObserver(this);

		// add notification when closing main frame
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				logger.info(Config.PROGRAM_NAME + " closed successfully");
			}
		});

		// Calculate size and position
		Dimension frameSize = new Dimension(900, 600);
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int left = (screenSize.width - frameSize.width) / 2;
		int top = (screenSize.height - frameSize.height) / 2;

		// Set size and position for the frame
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setPreferredSize(frameSize);
		setMinimumSize(frameSize);
		setLocation(left, top);

		// TopMenu
		MenuBar topMenu = new MenuBar(this, controller);
		controller.addObserver(topMenu);

		// NavigationBar
		NavigationBar navigationBar = new NavigationBar(controller);
		controller.addObserver(navigationBar);

		// content
		content = new JPanel(new BorderLayout());

		// Layout
		getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
		getContentPane().add(topMenu);
		getContentPane().add(navigationBar);
		getContentPane().add(content);

		// Set title and show frame
		updateTitle();
		pack();
		setVisible(true);
	}

	/**
	 * @param newContent the new panel to show
	 */
	private void setContent(ContentPanel newContent) {
		content.removeAll();
		// No view loaded
		if (newContent == null) {
			repaint();
			return;
		}
		// Set new view
		content.add(newContent, BorderLayout.CENTER);
		validate();
	}

	/**
	 * Switches view between data- and settingsview
	 */
	public void switchViewSettings() {
		if (!isContentCorrect())
			return;

		// No course loaded, can't switch
		if (!controller.courseLoaded())
			return;

		controller.switchShowConfig();
	}

	/**
	 * Creates a new course but doesn't save him yet
	 */
	public void newFile() {
		if (!isContentCorrect())
			return;

		controller.setShowConfig(true);
		controller.createNewCourse();
		setContent(new ContainerPanel(controller.getCourse(), controller));
	}

	/**
	 * Shows an {@link OpenFileChooser} to select a file to load
	 */
	public void openFile() {
		if (!isContentCorrect())
			return;

		controller.setShowConfig(false);

		boolean full = controller.hasFullAccess();

		FileType type = full ? FileType.MAIN : FileType.PART;
		OpenFileChooser fc = new OpenFileChooser(type, Config.OPEN_FC_TITLE);
		int result = fc.showOpenDialog(this);
		if (result == JFileChooser.APPROVE_OPTION) {
			controller.loadFile(fc.getSelectedFile());
			// There was an error loading the course
			if (controller.getCourse() == null) {
				logger.error("Error while opening Course");
				return;
			}
			ContentPanel content = full ? new ContainerPanel(controller.getCourse(), controller)
					: new SeriesView(controller.getCourse().getTheOnlySeries(), controller);
			setContent(content);
		}
	}

	/**
	 * Saves the currently opened course into a file
	 */
	public void saveFile() {
		if (!isContentCorrect())
			return;

		// No course loaded, can't save
		if (!controller.courseLoaded())
			return;

		// Check if the course really was saved yet
		if (controller.getCourseFile() == null)
			saveFileAs();
		else
			controller.saveFile();
	}

	/**
	 * Saves the currently opened course into a file the user selects
	 */
	public void saveFileAs() {
		if (!isContentCorrect())
			return;

		// No course loaded, can't save
		if (!controller.courseLoaded())
			return;

		// Show file chooser for save location
		SaveFileChooser fc = new SaveFileChooser(FileType.MAIN, Config.SAVE_FC_TITLE);
		fc.setSelectedFile(new File(controller.getSuggestedFileName(false)));
		int result = fc.showSaveDialog(this);
		if (result == JFileChooser.APPROVE_OPTION)
			controller.saveNewFile(fc.getSelectedFile());
	}

	public void saveAsCSV() {
		if (controller.getCourse() == null)
			return;

		List<CSVFile> files = controller.getCourse().getRepresentation(false, controller).toCSV("");
		for (CSVFile file : files) {
			System.out.println(file.getName().trim() + ".csv");
			System.out.println(file);
		}
	}

	/**
	 * Exports the selected series into a file
	 */
	public void exportFile() {
		if (!isContentCorrect())
			return;

		// No course loaded, can't export
		if (!controller.courseLoaded())
			return;

		SaveFileChooser fc = new SaveFileChooser(FileType.PART, Config.EXPORT_FC_TITLE);
		fc.setSelectedFile(new File(controller.getSuggestedFileName(true)));
		int result = fc.showSaveDialog(this);
		if (result == JFileChooser.APPROVE_OPTION)
			controller.exportFile(fc.getSelectedFile());
	}

	/**
	 * Imports a selected file and shows conflict handling routine afterwards
	 */
	public void importFile() {
		if (!isContentCorrect())
			return;

		// No course loaded, can't import
		if (!controller.courseLoaded())
			return;

		OpenFileChooser fc = new OpenFileChooser(FileType.PART, Config.IMPORT_FC_TITLE);
		fc.setSelectedFile(controller.getCourseFile());
		int result = fc.showOpenDialog(this);
		if (result == JFileChooser.APPROVE_OPTION)
			controller.importFile(fc.getSelectedFile());
	}

	private boolean isContentCorrect() {
		Component[] components = content.getComponents();
		if (components.length == 1 && components[0] instanceof ContentPanel) {
			ContentPanel curContent = (ContentPanel) components[0];

			if (curContent != null && !curContent.isCorrect()) {
				JOptionPane.showMessageDialog(this,
						"Bitte überprüfen Sie ihre aktuellen Eingaben, bevor Sie fortfahren.",
						"Eingaben nicht korrekt!", JOptionPane.WARNING_MESSAGE);
				return false;
			}
		}
		return true;
	}

	private void updateTitle() {
		Course course = controller.getCourse();
		String title = Config.PROGRAM_NAME + " " + Config.PROGRAM_VERSION;
		title += course != null ? " - " + course.getName() + " " + course.getTerm() : "";
		setTitle(title);
	}

	@Override
	public void notify(Observable<? extends HiCheckerEvent> sender, HiCheckerEvent event) {
		Course course = controller.getCourse();

		switch (event.getEventType()) {
		case SET_VIEWED_ELEMENT:
			// clear content if no course is loaded
			if (course == null)
				setContent(null);
			// set empty title
		case UPDATE_ITEM_NAME:
			updateTitle();
			break;
		}
	}

}
